
import 'dart:async';
import 'dart:convert';

import 'package:equatable/equatable.dart';
import 'package:flutter/widgets.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:flutter_webrtc/flutter_webrtc.dart';
import 'package:im_app/im/service/SoundService.dart';
import 'package:im_app/im/util/DialogUtil.dart';
import 'package:im_app/im/util/ImCacheFactory.dart';
import 'package:im_app/im/util/ImSingleton.dart';
import 'package:im_app/im/util/UiUtil.dart';

import '../../pojo/Enums.dart';
import '../../pojo/ImPojo.dart';
import '../../socket/dto/business/WebRtcData.dart';
import '../../socket/service/RpcSendDataService.dart';
import '../../util/LoggerUtil.dart';
import '../../webrtc/WebRtcClient.dart';
import '../../webrtc/WebRtcUiEvent.dart';
import 'BaseBloc.dart';

class WebRtcCubit extends BaseBloc<WebRtcEvent, WebRtcState> {

  final _logger = createLogger();
  Stopwatch? stopwatch = null;
  Timer? timer = null;
  SoundService soundService = SoundService();

  WebRtcCubit() : super(const WebRtcState.loading()) {

    on<WebRtcVideoInitEvent>((event, emit) {
      _initVideo(state, event.context, event.roomName, event.users, event.screenWidth, event.screenHeight);
    });
    on<WebRtcAudioInitEvent>((event, emit) {
      _initAudio(state, event.context, event.roomName, event.users, event.screenWidth, event.screenHeight);
    });
    on<WebRtcCloseEvent>((event, emit) {
      _exitRoom(state, event.context);
    });

    on<WebRtcSwitchVideoEvent>((event, emit) {
      _switchVideo(state);
    });
    on<WebRtcSwitchAudioEvent>((event, emit) {
      _switchAudio(state);
    });
    on<WebRtcSwitchVoiceOutputEvent>((event, emit) {
      _switchVoiceOutput(state);
    });
    on<WebRtcSwitchScreenSmallEvent>((event, emit) {
      _switchScreenSmall(state);
    });
    on<WebRtcInvitationEvent>((event, emit) {
      _invitationUsers(state, event.userIds, event.overlayEntry);
    });
    on<WebRtcInitiateEvent>((event, emit) {
      _initiateUsers(state, event.context, event.userIds, event.overlayEntry, event.isAudio, event.screenWidth,
          event.screenHeight);
    });
    on<WebRtcOverlayEvent>((event, emit) {
      _overlay(state, event.overlayEntry);
    });
    on<WebRtcAcceptInvitationEvent>((event, emit) {
      _accept(state, event.context, event.webRtcInvitationReq, event.screenWidth, event.screenHeight);
    });
    on<WebRtcRejectInvitationEvent>((event, emit) {
      _reject(state, event.context, event.webRtcInvitationReq);
    });
    on<WebRtcRefreshEvent>((event, emit) {
      _refresh(state);
    });
    on<WebRtcCancelEvent>((event, emit) {
      _cancel(state);
    });
  }

  Future<void> _initVideo(WebRtcState oldState, BuildContext context, String? roomNameParam, Set<ImUser> users,
      double screenWidth, double screenHeight) async {
    var userId = ImSingleton.getInstance().session.userId;
    var token = ImSingleton.getInstance().session.getData("authToken") as String;
    var tenantCode = ImSingleton.getInstance().session.getData("tenantCode") as String;
    var ip = ImSingleton.getInstance().session.getData("im_ip");

    var overlayEntry = oldState.overlayEntry;
    await _reset(oldState);

    var loginUser = await ImCacheFactory.getInstance().getImUser(userId!);

    try {
      var webRtcClient = WebRtcClient(loginUser!, token!, tenantCode!, 'ws://$ip:9890/signal', false,
        WebRtcUiEvent(receiveMedialStream: _receiveMediaStream, exitRoom: _exitRoomFromRemote), screenWidth, screenHeight);

      await webRtcClient!.start(roomNameParam);

      var joinRoomResult = await _loginAndInvitationOrJoin(webRtcClient, roomNameParam, false, users);
      if (joinRoomResult.roomName == null) {
        if (!joinRoomResult.isClose) {
          UiUtil.showSnackBar(ImSingleton.getInstance().mainContext!, '对方不在线，不能视频通信');
        }
        await _closeConnection(oldState);
      } else {
        var videoRenderer = await _addVideoRender(webRtcClient!.localMedialStream!);

        var roomName = joinRoomResult.roomName!;
        var mediaList = users.where((user)=>user.userId != userId)
            .map((user)=> WebRtcUserData(user, null, null, WebRtcUserDataStatus.connecting))
            .toList();
        emit(WebRtcState.init(WebRtcUserData(loginUser, videoRenderer, webRtcClient!.localMedialStream!,
            WebRtcUserDataStatus.connecting), LoadingState.success, webRtcClient, false, roomName, mediaList,
            context, overlayEntry, roomNameParam != null, true));
      }
    } catch (error) {
      var mediaList = users.where((user)=>user.userId != userId)
          .map((user)=> WebRtcUserData(user, null, null, WebRtcUserDataStatus.connecting)).toList();
      emit(state.copy(isAccept: roomNameParam != null, mediaList: mediaList));
      _logger.e('[WebRtcCubit init video error]', error: error);
    }
  }

  Future<void> _initAudio(WebRtcState oldState, BuildContext context, String? roomNameParam, Set<ImUser> users,
      double screenWidth, double screenHeight) async {
    var userId = ImSingleton.getInstance().session.userId;
    var token = ImSingleton.getInstance().session.getData("authToken") as String;
    var tenantCode = ImSingleton.getInstance().session.getData("tenantCode") as String;
    var ip = ImSingleton.getInstance().session.getData("im_ip");

    var overlayEntry = oldState.overlayEntry;
    await _reset(oldState);

    var loginUser = await ImCacheFactory.getInstance().getImUser(userId!);

    var webRtcClient = WebRtcClient(loginUser!, token!, tenantCode!, 'ws://$ip:9890/signal', true,
      WebRtcUiEvent(receiveMedialStream: _receiveMediaStream, exitRoom: _exitRoomFromRemote), screenWidth, screenHeight);

    await webRtcClient!.start(roomNameParam);

    var joinRoomResult = await _loginAndInvitationOrJoin(webRtcClient, roomNameParam, true, users);
    if (joinRoomResult.roomName == null) {
      await _closeConnection(oldState);
      if (!joinRoomResult.isClose) {
        UiUtil.showSnackBar(ImSingleton.getInstance().mainContext!, '对方不在线，不能视频通信');
      }
    } else {
      var roomName = joinRoomResult.roomName!;
      var mediaList = users.where((user)=>user.userId != userId)
          .map((user)=> WebRtcUserData(user, null, null, WebRtcUserDataStatus.connecting)).toList();
      var lastedState = WebRtcState.init(WebRtcUserData(loginUser!, null, webRtcClient!.localMedialStream!, WebRtcUserDataStatus.connecting),
          LoadingState.success, webRtcClient, true, roomName, mediaList, context, overlayEntry, roomNameParam != null, roomNameParam != null);
      emit(lastedState);
    }
  }

  void _switchVideo(WebRtcState oldState) {
    var isCloseVideo = oldState.isCloseVideo;
    if (oldState.webRtcClient != null) {
      if (isCloseVideo) {
        oldState.webRtcClient!.openVideo();
      } else {
        oldState.webRtcClient!.closeVideo();
      }
    }
    emit(oldState.copy(isCloseVideo: !isCloseVideo));
  }

  void _switchAudio(WebRtcState oldState) {
    var isCloseAudio = oldState.isCloseAudio;
    if (oldState.webRtcClient != null) {
      if (isCloseAudio) {
        oldState.webRtcClient!.openAudio();
      } else {
        oldState.webRtcClient!.closeAudio();
      }
    }
    emit(oldState.copy(isCloseAudio: !isCloseAudio));
  }

  void _switchVoiceOutput(WebRtcState oldState) async {
    var isVoiceOutput = oldState.isVoiceOutput;
    if (oldState.webRtcClient != null) {
      await oldState.webRtcClient!.switchVoice();
    }
    emit(oldState.copy(isVoiceOutput: !isVoiceOutput));
  }

  void _switchScreenSmall(WebRtcState oldState) {
    var isScreenSmall = oldState.isScreenSmall;
    emit(oldState.copy(isScreenSmall: !isScreenSmall));
  }

  // 被邀请视频聊天
  void _invitationUsers(WebRtcState oldState, Set<String> userIds, OverlayEntry overlayEntry) async {
    var users = <ImUser>[];
    for (var userId in userIds) {
      var user = await ImCacheFactory.getInstance().getImUser(userId);
      users.add(user!);
    }

    // ImSingleton.getInstance().session.putData("webRtcOverlay", overlayEntry);
    var mediaList = users.map((u)=>WebRtcUserData(u, null, null, WebRtcUserDataStatus.init)).toList();
    var newState = oldState.copy(mediaList: mediaList, overlayEntry: overlayEntry, isAccept: true);
    emit(newState);
    soundService.playSource("assets/media/call.mp3");
  }

  // 主动发起视频聊天
  void _initiateUsers(WebRtcState oldState, BuildContext context, Set<ImUser> users, OverlayEntry overlayEntry,
      bool isAudio, double screenWidth, double screenHeight) async {
    var mediaList = users.map((u)=>WebRtcUserData(u, null, null, WebRtcUserDataStatus.init)).toList();
    var newState = oldState.copy(mediaList: mediaList, overlayEntry: overlayEntry);
    if (isAudio) {
      await _initAudio(newState, context, null, users, screenWidth, screenHeight);
    } else {
      await _initVideo(newState, context, null, users, screenWidth, screenHeight);
    }
    await soundService.playSource("assets/media/call.mp3");
  }

  void _overlay(WebRtcState oldState, OverlayEntry overlayEntry) async {
    emit(oldState.copy(overlayEntry: overlayEntry));
  }

  void _receiveMediaStream(String userId, String kind, MediaStream mediaStream) async {
    _logger.i('[WebRtcCubit receive mediaStream], kind: $kind, userId: $userId');
    soundService.stop();
    if (kind == 'video') {
      var videoRender = await _addVideoRender(mediaStream);
      var mediaList = <WebRtcUserData>[];
      for (var media in state.mediaList) {
        if (media.user.userId == userId) {
          mediaList.add(WebRtcUserData(media.user, videoRender, mediaStream, WebRtcUserDataStatus.connected));
        } else {
          mediaList.add(media);
        }
      }

      emit(state.copy(mediaList: mediaList));
    } else if (kind == 'audio') {
      if (state.isAudio) {
        var mediaList = <WebRtcUserData>[];
        for (var media in state.mediaList) {
          if (media.user.userId == userId) {
            mediaList.add(WebRtcUserData(media.user, null, mediaStream, WebRtcUserDataStatus.connected));
          } else {
            mediaList.add(media);
          }
        }
        emit(state.copy(mediaList: mediaList));

        _startTimer(state);
      }
    }
  }

  // 接受到用户退群
  void _exitRoomFromRemote(String userId) async {
    var mediaList = state.mediaList;
    var newMediaList = <WebRtcUserData>[];
    for (var media in mediaList) {
      if (media.user.userId == userId) {
        await _closeMedia(media);
        var newMedia = WebRtcUserData(media.user, null, null, WebRtcUserDataStatus.offline);
        newMediaList.add(newMedia);
      } else {
        newMediaList.add(media);
      }
    }
    if(newMediaList.where((media)=>media.status != WebRtcUserDataStatus.offline).isEmpty) { // 都离线了，就关闭视频
      await _closeConnection(state);
    } else {
      emit(state.copy(mediaList: newMediaList));
    }
  }

  Future<RTCVideoRenderer> _addVideoRender(MediaStream mediaStream) async {
    var videoRenderer = RTCVideoRenderer();
    await videoRenderer.initialize();

    videoRenderer.srcObject = mediaStream;
    return videoRenderer;
  }

  void _exitRoom(WebRtcState oldState, BuildContext context) async {
    try {
      var connectionUsers = oldState.webRtcClient?.getConnectionUsers();
      var notConnectionUsers = Set<String>();
      for (var media in oldState.mediaList) {
        if (!(connectionUsers?.contains(media.user.userId)??false)) {
          notConnectionUsers.add(media.user.userId);
        }
      }
      // 向未建立连接的用户发起取消请求
      _sendWebRtcCancel(notConnectionUsers);

      if (!(oldState.closed || ((oldState.webRtcClient?.isClosing)??true))) {
        await oldState.webRtcClient!.exitRoom();
      }
    } catch (error) {
      _logger.e('[WebRtcCubit exit room error]', error: error);
    }

    _closeConnection(oldState);
  }

  Future<JoinRoomResult> _loginAndInvitationOrJoin(WebRtcClient webRtcClient, String? troomName, bool isAudio,
      Set<ImUser> userSet) async {
    var roomName = troomName;
    bool isClose = false;
    if (troomName == null) { // 发起者
      roomName = await webRtcClient.createRoom();

      ChatType chatType = isAudio ? ChatType.audio : ChatType.video;
      var userIdSet = userSet.map((u)=>u.userId).toSet();
      var invitationReq = WebRtcInvitationReq(roomName: roomName, chatType: chatType, userIds: userIdSet);

      RpcWebRtcService rpcWebRtcService = RpcWebRtcService();
      var invitationResultList = await rpcWebRtcService.sendWebRtcInvitation(invitationReq);
      var length = invitationResultList.invitationResultList.where((invitationResult)=>invitationResult.isOffline).length;
      var userSize = userSet.length;
      var loginUserId = ImSingleton.getInstance().session.userId!;
      if (userIdSet.contains(loginUserId)) {
        userSize -= 1;
      }
      if (length == userSize) {
        return JoinRoomResult(null, isClose);
      }
    } else { // 接受邀请，进入房间
      var webRtcRoomInfo = await webRtcClient.joinRoom(roomName!);
      if (webRtcRoomInfo.userInfoList == null || webRtcRoomInfo.userInfoList.isEmpty) { // 房间已经退出了
        isClose = true;
        roomName = null;
      }
    }
    return JoinRoomResult(roomName, isClose);
  }

  void _sendWebRtcCancel(Set<String> userIds) async {
    _logger.i('[WebRtcCubit send cancel req], size: ${userIds.length}');
    if (userIds.isEmpty) return;
    var cancelReq = WebRtcCancelReq(userIds: userIds);

    RpcWebRtcService rpcWebRtcService = RpcWebRtcService();
    var okResp = await rpcWebRtcService.sendWebRtcCancel(cancelReq);
    _logger.i('[WebRtcCubit send cancel req], result: ${jsonEncode(okResp)}');
  }

  // 接受视频邀请
  void _accept(WebRtcState oldState, BuildContext context, WebRtcInvitationReq invitationReq, double screenWidth,
      double screenHeight) async {
    try {
      soundService.stop();
      var rpcWebRtcService = RpcWebRtcService();
      rpcWebRtcService.sendWebRtcInvitationResult(WebRtcInvitationResultReq(toUserId: invitationReq!.fromUserId!, isAccept: true))
          .then((okResp) => _logger.i('[WebRtcClient accept invitation], success'));

      var loginUserId = ImSingleton.getInstance().session.userId;
      var userSet = <ImUser>{};
      for (var userId in invitationReq!.userIds) {
        if (userId == loginUserId) continue;
        var user = await ImCacheFactory.getInstance().getImUser(userId);
        userSet.add(user!);
      }
      var fromUser = await ImCacheFactory.getInstance().getImUser(invitationReq!.fromUserId!);
      userSet.add(fromUser!);

      var webRtcCubit = context.read<WebRtcCubit>();
      if (invitationReq!.chatType == ChatType.audio) {
        webRtcCubit.add(WebRtcAudioInitEvent(context, invitationReq!.roomName, userSet, screenWidth, screenHeight));
      } else {
        webRtcCubit.add(WebRtcVideoInitEvent(context, invitationReq!.roomName, userSet, screenWidth, screenHeight));
      }
    } catch (error) {
      _logger.e("[WebRtcBaseView accept error]", error: error);
    }
  }

  /// 拒绝视频邀请
  void _reject(WebRtcState oldState, BuildContext context, WebRtcInvitationReq invitationReq) {
    var rpcWebRtcService = RpcWebRtcService();
    rpcWebRtcService.sendWebRtcInvitationResult(
        WebRtcInvitationResultReq(toUserId: invitationReq!.fromUserId!, isAccept: false))
        .then((okResp) => _logger.i('[WebRtcClient reject invitation], success'));

    _closeOverlayEntry(oldState);
  }

  void _refresh(WebRtcState oldState) {
    if (stopwatch?.isRunning??false) {
      var timeFormat = (stopwatch!.elapsed.inMinutes % 60).toString().padLeft(2, "0") + ":" +
          (stopwatch!.elapsed.inSeconds % 60).toString().padLeft(2, "0");
      emit(oldState.copy(timeFormat: timeFormat));
    }
  }

  void _cancel(WebRtcState oldState) async {
    await _closeConnection(oldState);
  }

  void _startTimer(WebRtcState oldState) {
    stopwatch = Stopwatch();
    stopwatch?.start();
    timer = Timer.periodic(const Duration(seconds: 1), (timer)=>_updateTimer(timer));
  }

  void _updateTimer(Timer timer) {
    _logger.i("refresh!!!!!!!!!!!!!");
    if (stopwatch?.isRunning?? false) {
      add(WebRtcRefreshEvent());
    }
  }

  // 关闭连接
  Future<void> _closeConnection(WebRtcState oldState) async {
    await _reset(oldState);
    _closeOverlayEntry(oldState);
    await oldState.webRtcClient?.close();
    emit(const WebRtcState.loading());
  }

  // 重置WebRtcCubit
  Future<void> _reset(WebRtcState oldState) async {
    _logger.i("[WebRtcCubit reset], !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!");
    soundService.stop();
    if (oldState.webRtcClient != null) {
      await oldState.webRtcClient!.close();
    }
    if (oldState.localMediaData != null) {
      await oldState.localMediaData!.videoRenderer?.dispose();
    }
    for (var data in oldState.mediaList) {
      await _closeMedia(data);
    }

    timer?.cancel();
    stopwatch?.stop();
    _logger.i("[WebRtcCubit reset success], !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!");
  }

  // 关闭视频Ui
  void _closeOverlayEntry(WebRtcState oldState) {
    try {
      if (oldState.overlayEntry != null && oldState.overlayEntry!.mounted) {
        removeOverlay(oldState.overlayEntry!);
        ImSingleton.getInstance().session.delete("webRtcOverlay");
      }
      var overlayEntry = ImSingleton.getInstance().session.delete("webRtcOverlay");
      if (overlayEntry != null) {
        var overlayEntryTmp = overlayEntry as OverlayEntry;
        overlayEntryTmp.remove();
        overlayEntryTmp.dispose();
      }
    } catch (error) {
      _logger.e("[WebRtcCubit close overlay]", error: error);
    }
  }

  // 关闭某个连接
  Future<void> _closeMedia(WebRtcUserData media) async {
    if (media.videoRenderer != null) {
      await media.videoRenderer?.dispose();
    }
  }

  @override
  Future<void> close() {
    _logger.i("[WebRtcCubit close], !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!");
    _reset(state);
    _closeOverlayEntry(state);
    return super.close();
  }
}

final class WebRtcState extends Equatable {
  final LoadingState state;
  final List<WebRtcUserData> mediaList;
  final WebRtcUserData? localMediaData;
  final WebRtcClient? webRtcClient;
  final bool isCloseVideo;              // 是否关闭视频
  final bool isCloseAudio;              // 是否关闭语音
  final bool isAudio;                   // 是否仅仅语音聊天
  final bool isAccept;                  // 是否视频接受者
  final bool isAccepted;                // 是否已经接受视频邀请
  final bool isVoiceOutput;             // 是否语音外放
  final String? roomName;
  final bool closed;
  final BuildContext? context;
  final String timeFormat;
  final OverlayEntry? overlayEntry;
  final bool isScreenSmall;                          // 是否小框模式。

  const WebRtcState._({
    this.state = LoadingState.loading,
    this.mediaList = const <WebRtcUserData>[],
    this.localMediaData = null,
    this.webRtcClient = null,
    this.isCloseVideo = false,
    this.isCloseAudio = false,
    this.isAudio = false,
    this.isAccept = false,
    this.isAccepted = false,
    this.roomName = null,
    this.closed = false,
    this.context = null,
    this.timeFormat = '',
    this.isVoiceOutput = false,
    this.overlayEntry = null,
    this.isScreenSmall = false,
  });

  static create(String? roomName, bool isAudio, List<WebRtcUserData> webRtcUserDatas) {
    return WebRtcState._(roomName: roomName, isAudio: isAudio, mediaList: webRtcUserDatas);
  }

  const WebRtcState.loading() : this._();

  const WebRtcState.init(WebRtcUserData localVideoData, LoadingState state, WebRtcClient webRtcClient, bool isAudio,
      String roomName, List<WebRtcUserData> mediaList, BuildContext context, OverlayEntry? overlayEntry,
      bool isAccept, bool isAccepted) : this._(
      localMediaData: localVideoData, state: state, webRtcClient: webRtcClient, roomName: roomName,
    context:  context, mediaList: mediaList, isAudio: isAudio,
    isScreenSmall: false, overlayEntry: overlayEntry, isAccept: isAccept, isAccepted: isAccepted
  );

  WebRtcState copy({LoadingState? state, List<WebRtcUserData>? mediaList, WebRtcUserData? localMediaData,
    MediaStream? localMediaStream, WebRtcClient? webRtcClient, bool? isCloseVideo, bool? isCloseAudio,
    String? roomName, bool? closed, BuildContext? context, String? timeFormat, bool? isVoiceOutput,
    OverlayEntry? overlayEntry, bool? isScreenSmall, bool? isAccept, bool? isAccepted}) {
    return WebRtcState._(
      state: state ?? this.state,
      mediaList: mediaList ?? this.mediaList,
      localMediaData: localMediaData ?? this.localMediaData,
      webRtcClient: webRtcClient ?? this.webRtcClient,
      isCloseVideo: isCloseVideo ?? this.isCloseVideo,
      isCloseAudio: isCloseAudio ?? this.isCloseAudio,
      roomName: roomName ?? this.roomName,
      closed: closed ?? this.closed,
      context: context ?? this.context,
      isAudio: this.isAudio,
      timeFormat: timeFormat ?? this.timeFormat,
      isVoiceOutput: isVoiceOutput ?? this.isVoiceOutput,
      overlayEntry: overlayEntry ?? this.overlayEntry,
      isScreenSmall: isScreenSmall ?? this.isScreenSmall,
      isAccept: isAccept ?? this.isAccept,
      isAccepted: isAccepted ?? this.isAccepted,
    );
  }

  @override
  List<Object?> get props => [state, mediaList, localMediaData, isCloseVideo, isCloseAudio, timeFormat,
    isVoiceOutput, isScreenSmall, roomName];
}

final class WebRtcUserData extends Equatable{
  final ImUser user;
  RTCVideoRenderer? videoRenderer;
  MediaStream? mediaStream;
  WebRtcUserDataStatus status;                     // 用户是否已经建立连接

  WebRtcUserData(this.user, this.videoRenderer, this.mediaStream, this.status);

  @override
  List<Object?> get props => [user, status];
}

abstract class WebRtcEvent {}
final class WebRtcVideoInitEvent extends WebRtcEvent {
  final BuildContext context;
  final String? roomName;
  final Set<ImUser> users;
  final double screenWidth;
  final double screenHeight;
  WebRtcVideoInitEvent(this.context, this.roomName, this.users, this.screenWidth, this.screenHeight);
}
final class WebRtcAudioInitEvent extends WebRtcEvent {
  final BuildContext context;
  final String? roomName;
  final Set<ImUser> users;
  final double screenWidth;
  final double screenHeight;
  WebRtcAudioInitEvent(this.context, this.roomName, this.users, this.screenWidth, this.screenHeight);
}
final class WebRtcCloseEvent extends WebRtcEvent {
  final BuildContext context;
  WebRtcCloseEvent(this.context);
}
final class WebRtcSwitchVideoEvent extends WebRtcEvent {}
final class WebRtcSwitchAudioEvent extends WebRtcEvent {}

// 打开外放
final class WebRtcSwitchVoiceOutputEvent extends WebRtcEvent {}
final class WebRtcSwitchScreenSmallEvent extends WebRtcEvent {}

final class WebRtcAcceptInvitationEvent extends WebRtcEvent {
  final WebRtcInvitationReq webRtcInvitationReq;
  final BuildContext context;
  final double screenWidth;
  final double screenHeight;
  WebRtcAcceptInvitationEvent(this.webRtcInvitationReq, this.context, this.screenWidth, this.screenHeight);
}
final class WebRtcRejectInvitationEvent extends WebRtcEvent {
  final WebRtcInvitationReq webRtcInvitationReq;
  final BuildContext context;
  WebRtcRejectInvitationEvent(this.webRtcInvitationReq, this.context);
}

// 接受用户邀请视频聊天
final class WebRtcInvitationEvent extends WebRtcEvent {
  Set<String> userIds;
  OverlayEntry overlayEntry;
  WebRtcInvitationEvent(this.userIds, this.overlayEntry);
}

// 发起视频聊天
final class WebRtcInitiateEvent extends WebRtcEvent {
  final BuildContext context;
  final Set<ImUser> userIds;
  final OverlayEntry overlayEntry;
  final bool isAudio;
  final double screenWidth;
  final double screenHeight;
  WebRtcInitiateEvent(this.context, this.userIds, this.overlayEntry, this.isAudio, this.screenWidth, this.screenHeight);
}
final class WebRtcOverlayEvent extends WebRtcEvent {
  OverlayEntry overlayEntry;
  WebRtcOverlayEvent(this.overlayEntry);
}

final class WebRtcRefreshEvent extends WebRtcEvent {}
final class WebRtcCancelEvent extends WebRtcEvent {}

// 申请进入房间结果
class JoinRoomResult {
  final String? roomName;
  final bool isClose;         // 是否已经关闭

  JoinRoomResult(this.roomName, this.isClose);
}

enum WebRtcUserDataStatus {
  init,            // 初始状态
  connecting,      // 连接中
  connected,       // 已连接
  offline,         // 未在线
}


